package com.xjgc.webservice;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.JVM;
import com.thoughtworks.xstream.io.xml.StaxDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import com.xjgc.msibase.entity.MsiServerRecord;
import com.xjgc.msibase.entity.MsiServerRecordInfo;
import com.xjgc.msibase.service.IMsiServerRecordInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ClassUtils;
import org.jeecg.common.util.SpringContextUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: 小逗号
 * @date: 2023-11-8
 * @description:
 * @since:
 */
@Slf4j
public class XmlUtils {


    private static IMsiServerRecordInfoService msiServerRecordInfoService;

    private static IMsiServerRecordInfoService getRecordInfoService() {
        if (msiServerRecordInfoService == null) {
            msiServerRecordInfoService = SpringContextUtils.getBean(IMsiServerRecordInfoService.class);
        }
        return msiServerRecordInfoService;
    }

    private static final XStream X_STREAM = new XStream(new StaxDriver(new XmlFriendlyNameCoder("_-", "_")));

    static {
        X_STREAM.ignoreUnknownElements();
        X_STREAM.autodetectAnnotations(true);
    }


    public static String toXml(Object object) {
        long start = System.currentTimeMillis();
        String xml = X_STREAM.toXML(object);
        long end = System.currentTimeMillis();
        log.info("{}序列化Xml耗时:{} ms", object.getClass().getSimpleName(), (end - start));
        return xml;
    }

    public static String toXml(MsiServerRecord record, Object object) {
        String xml = toXml(object);
        getRecordInfoService().add(record.getId(), new Date(), MsiServerRecordInfo.Node.TO_XML);
        return xml;
    }

    public static XParam fromXml(MsiServerRecord record, String className, String xml) {
        Class<XParam> aClass = getClass(className);
        return fromXml(record, aClass, xml);
    }

    public static XParam fromXml(MsiServerRecord record, Class<XParam> pClass, String xml) {
        long start = System.currentTimeMillis();
        XStream xStream = getXStream(pClass.getName());
        Object o = xStream.fromXML(xml);
        XParam p = (XParam) o;
        long end = System.currentTimeMillis();
        log.info("Xml返序列化{}耗时:{} ms", p.getClass().getSimpleName(), (end - start));
        //getRecordInfoService().add(record.getId(), new Date(), MsiServerRecordInfo.Node.PARSE_XML);
        return p;
    }

    static class Mapper<E extends XParam> {
        String className;
        Class<E> aClass;
        XStream xStream;
    }

    private static final Map<String, Mapper<XParam>> MAPPER_MAP = new HashMap<>(16);

    private static Mapper<XParam> getMapper(String className) {
        if (!MAPPER_MAP.containsKey(className)) {
            Mapper<XParam> mapper = new Mapper();
            mapper.className = className;
            Class aClass = JVM.loadClassForName(className);
            if (aClass != null && ClassUtils.getAllSuperclasses(aClass).contains(XParam.class)) {
                Class<XParam> pClass = (Class<XParam>) aClass;
                mapper.aClass = aClass;
                XStream xStream = new XStream(new StaxDriver(new XmlFriendlyNameCoder("_-", "_")));
                //统一日期格式转换
                //xStream.registerConverter(new DateConverter("yyyyMMdd", null, TimeZone.getTimeZone("GMT+8")));
                //加载默认
                //XStream.setupDefaultSecurity(XSTREAM_AUTODETECT_ANNOTATION);
                //忽略未知标签
                xStream.ignoreUnknownElements();
                //开启注解扫描,指定扫描Class
                xStream.processAnnotations(aClass);
                mapper.xStream = xStream;
            }
            MAPPER_MAP.put(className, mapper);
        }
        return MAPPER_MAP.get(className);
    }

    private static XStream getXStream(String className) {
        Mapper<XParam> mapper = getMapper(className);
        return mapper.xStream;
    }

    public static Class<XParam> getClass(String className) {
        Mapper<XParam> mapper = getMapper(className);
        return mapper.aClass;
    }


}
